package cn.edu.sgu.www.mhxysy.aop;

import cn.edu.sgu.www.mhxysy.consts.IdentifierPrefixes;
import cn.edu.sgu.www.mhxysy.mongo.OperateLog;
import cn.edu.sgu.www.mhxysy.redis.RedisUtils;
import cn.edu.sgu.www.mhxysy.util.HttpUtils;
import cn.edu.sgu.www.mhxysy.util.IpUtils;
import cn.edu.sgu.www.mhxysy.util.StringUtils;
import cn.edu.sgu.www.mhxysy.util.UserUtils;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.subject.Subject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;

/**
 * 用于记录日志的AOP切面类
 * @author 沐雨橙风ιε
 * @version 1.0
 */
@Aspect
@Component
@ConditionalOnProperty(prefix = "system.settings", name = "enable-log", havingValue = "true", matchIfMissing = false)
public class LogAspect {

    private final RedisUtils redisUtils;
    private final MongoTemplate mongoTemplate;

    @Autowired
    public LogAspect(RedisUtils redisUtils, MongoTemplate mongoTemplate) {
        this.redisUtils = redisUtils;
        this.mongoTemplate = mongoTemplate;
    }

    @Around("Pointcuts.controllerPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        String requestURI = HttpUtils.getRequestURI();

        /*
         * 保存日志到MongoDB
         * 查询类请求不记录日志
         */
        if (!requestURI.contains("get") && !requestURI.contains("select")) {
            OperateLog operateLog = new OperateLog();

            operateLog.setId(uuid());
            operateLog.setClientIp(IpUtils.getIp());
            operateLog.setOperateUrl(requestURI);
            operateLog.setBrowserType(IpUtils.getBrowserType());
            operateLog.setOperateTime(StringUtils.toTimeString(LocalDateTime.now()));

            /*
             * 设置操作用户
             */
            Subject subject = UserUtils.getSubject();

            // 用户已经登录，设置用户ID和用户名
            if (subject.isAuthenticated()) {
                operateLog.setUserId(UserUtils.getUserId());
                operateLog.setUsername(UserUtils.getLoginUsername());
            }

            /*
             * 设置请求参数
             */
            Object[] args = joinPoint.getArgs();
            String requestArgs = null;

            if (args != null && args.length > 0) {
                requestArgs = Arrays.toString(args);
            }

            operateLog.setRequestParams(requestArgs);

            /*
             * 设置操作名称
             */
            // 获取方法签名
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();

            // 获取方法上的@ApiOperation注解
            Method method = signature.getMethod();

            if (method.isAnnotationPresent(ApiOperation.class)) {
                ApiOperation annotation = method.getDeclaredAnnotation(ApiOperation.class);

                operateLog.setOperateName(annotation.value());
            }

            mongoTemplate.insert(operateLog);
        }

        return joinPoint.proceed();
    }

    private String uuid() {
        return IdentifierPrefixes.PREFIX_OPERATE_LOG + redisUtils.uuid();
    }

}